package com.yanqu.road.server.gameplayer.module.vehicle;

import com.alibaba.fastjson.JSONObject;
import com.yanqu.road.dao.impl.player.UserVehicleBoneDaoImpl;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.skill.SkillInfo;
import com.yanqu.road.entity.config.skill.SkillUpgradeInfo;
import com.yanqu.road.entity.config.vehicle.VehicleInfo;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.log.LogVehicleBoneEquip;
import com.yanqu.road.entity.log.LogVehicleBoneLvUp;
import com.yanqu.road.entity.log.LogVehicleBoneRecycle;
import com.yanqu.road.entity.log.LogVehicleBoneSkillUp;
import com.yanqu.road.entity.player.UserVehicle;
import com.yanqu.road.entity.player.UserVehicleBone;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.VehiclePb;
import com.yanqu.road.pb.vehicle.VehicleProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.patrons.PatronsModule;
import com.yanqu.road.server.gameplayer.module.player.AttributeModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.config.*;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class VehicleBoneModule extends GeneralModule {
    public VehicleBoneModule(GamePlayer player) {
        super(player);
    }

    private Map<Integer, UserVehicleBone> boneMap = new ConcurrentHashMap<>();

    private Map<String, List<UserVehicleBone>> equipBoneMap = new ConcurrentHashMap<>();

    private AtomicInteger boneAtoId = new AtomicInteger(1);
    private Set<UserVehicleBone> cacheSyncSet = new HashSet<>();

    @Override
    public boolean loadData() {
        boneMap = new UserVehicleBoneDaoImpl().getUserVehicleBone(getUserId());
        boneAtoId = new AtomicInteger(new UserVehicleBoneDaoImpl().getUserVehicleBoneMaxId(getUserId()) + 1);

        Map<String, List<UserVehicleBone>> tempMap = new ConcurrentHashMap<>();
        for (UserVehicleBone userVehicleBone : boneMap.values()) {
            if (StringUtils.isNullOrEmpty(userVehicleBone.getVehicleId())) {
                continue;
            }
            List<UserVehicleBone> list = tempMap.getOrDefault(userVehicleBone.getVehicleId(), new ArrayList<>());
            list.add(userVehicleBone);
            tempMap.put(userVehicleBone.getVehicleId(), list);
        }
        equipBoneMap = tempMap;
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        List<Integer> needRemoveIds = new ArrayList<>();
        for (UserVehicleBone vehicleBone : boneMap.values()) {
            if (vehicleBone.isInsertOption()) {
                new UserVehicleBoneDaoImpl().add(vehicleBone);
            } else if (vehicleBone.isUpdateOption()) {
                new UserVehicleBoneDaoImpl().update(vehicleBone);
            }

            if (vehicleBone.isDelete()) {
                needRemoveIds.add(vehicleBone.getBoneId());
            }
        }

        for (Integer id : needRemoveIds) {
            boneMap.remove(id);
        }
        return true;
    }

    @Override
    public void loginSendMsg() {

    }

    @Override
    public void afterLogin() {
        syncUserData();
    }

    public void initSystem() {
        if (!isSystemOpen()) {
            return;
        }

        List<UserVehicle> changeList  = new ArrayList<>();
        List<UserVehicle> userPatronsList = new ArrayList<>(player.getModule(VehicleModule.class).getUserVehicleMap().values());
        for (UserVehicle userVehicle : userPatronsList) {
            VehicleInfo vehicleInfo = VehicleMgr.getVehicleInfo(userVehicle.getTemplateId());
            if (vehicleInfo == null) {
                continue;
            }
            if (vehicleInfo.getBonePowerSkill() > 0 && userVehicle.getBoneLv() == 0) {
                userVehicle.setBoneLv(1);
                if (VehicleBoneConfigMgr.isHoleUnlock(userVehicle.getBoneLv(), 1)) {
                    userVehicle.setBoneHole(1);//第一个孔默认解锁
                }
                changeList.add(userVehicle);
            }
        }

        if (!changeList.isEmpty()) {
            player.sendPacket(Protocol.U_VEHICLE_SYNC, VehiclePb.parseVehicleListMsg(changeList));
        }
    }

    public boolean isSystemOpen() {
        return SystemOpenMgr.systemOpen(player, eSystemId.VehicleBone.getValue());
    }

    public void initUserData() {
        if (!isSystemOpen()) {
            return;
        }
    }

    public void syncUserData() {
        syncBoneData(new ArrayList<>(boneMap.values()));
    }

    public void syncBoneData(List<UserVehicleBone> userVehicleBones) {
        VehicleProto.VehicleBoneSyncMsg.Builder syncMsg = VehicleBonePb.parseStoneSyncBuilder(userVehicleBones);
        player.sendPacket(GameProtocol.S_VBONE_SYNC % 20000, syncMsg);
    }

    public Map<Integer, UserVehicleBone> getBoneMap() {
        return boneMap;
    }

    public Map<Integer, UserVehicleBone> getAllEquipBoneMap() {
        Map<Integer, UserVehicleBone> tempMap = new HashMap<>();
        for (UserVehicleBone vehicleBone : boneMap.values()) {
            if (StringUtils.isNullOrEmpty(vehicleBone.getVehicleId())) {
                continue;
            }
            tempMap.put(vehicleBone.getBoneId(), vehicleBone);
        }

        return tempMap;
    }

    public UserVehicleBone getBoneData(int boneId) {
        return boneMap.get(boneId);
    }

    public List<UserVehicleBone> getEquipBoneList(String vehicleId) {
        if (equipBoneMap.containsKey(vehicleId)) {
            return new ArrayList<>(equipBoneMap.get(vehicleId));
        }
        return new ArrayList<>();
    }

    /**
     * 炼魂升级
     *
     * @param vehicleId
     * @param times
     * @return
     */
    public int vehicleBoneLvUp(String vehicleId, int times) {
        if (!isSystemOpen()) {
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        UserVehicle userVehicle = player.getModule(VehicleModule.class).getUserVehicle(vehicleId);
        if (userVehicle == null) {
            return GameErrorCode.E_VEHICLE_NO_FOUND;
        }

        if (times < 0 || times > 10) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }

        VehicleInfo vehicleInfo = VehicleMgr.getVehicleInfo(userVehicle.getTemplateId());
        if (vehicleInfo == null) {
            return GameErrorCode.E_VEHICLE_NO_FOUND;
        }

        SkillInfo skillInfo = SkillMgr.getSkillInfo(vehicleInfo.getBonePowerSkill());
        if (skillInfo == null) {
            return GameErrorCode.E_VEHICLE_SKILL_NO_FOUND;
        }

        int startLv = userVehicle.getBoneLv();
        if (startLv >= skillInfo.getMaxLevel()) {
            return GameErrorCode.E_LEVEL_MAX;
        }

        Property preCost = new Property();
        Property realCost = new Property();
        int endLv = startLv;
        for (endLv = startLv; endLv < startLv + times && endLv < skillInfo.getMaxLevel(); endLv++) {
            SkillUpgradeInfo skillUpgradeInfo = SkillMgr.getSkillUpgradeInfo(skillInfo.getUpgradeType(0), endLv);
            if (skillUpgradeInfo == null) {
                break;
            }
            Property lvUpCost = new Property(skillInfo.getConsumeGoodsId().get(0), skillUpgradeInfo.getConsumeCount());
            preCost.addProperty(lvUpCost);
            if (!player.getModule(CurrencyModule.class).currencyIsEnough(preCost)) {
                break;
            }
            realCost.addProperty(lvUpCost);
        }

        if (endLv == startLv) {
            player.notifyListener(eGamePlayerEventType.VehicleBoneRechargeTrigger.getValue(), 0);
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        if (!player.getModule(CurrencyModule.class).removeCurrency(realCost, eLogMoneyType.VehicleBone, eLogMoneyType.VehicleBoneLvUpCost)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        userVehicle.setBoneLv(endLv);

        if (userVehicle.getPatronsId() > 0) {
            player.getModule(PatronsModule.class).syncPatronsCache(userVehicle.getPatronsId());
        }

        VehicleProto.VehicleBoneLvUpRespMsg.Builder resp = VehicleProto.VehicleBoneLvUpRespMsg.newBuilder();
        resp.setRet(0);
        resp.setVehicleId(vehicleId);
        resp.setEndLv(endLv);
        player.sendPacket(GameProtocol.S_VBONE_LV_UP % 20000, resp);

        AutoLogMgr.add(new LogVehicleBoneLvUp(player.getUserId(), userVehicle.getVehicleUid(), userVehicle.getTemplateId(), endLv, realCost.toHelperString()));
        return 0;
    }

    /**
     * 判断珍兽是否已装备魂骨
     *
     * @param userVehicle
     * @param pos
     * @return
     */
    public UserVehicleBone getVehicleEquipBone(UserVehicle userVehicle, int pos) {
        List<UserVehicleBone> equipBoneList = getEquipBoneList(userVehicle.getVehicleUid());
        if (equipBoneList == null) {
            return null;
        }
        for (UserVehicleBone userVehicleBone : equipBoneList) {
            if (userVehicleBone.getEquipPos() == pos) {
                return userVehicleBone;
            }
        }
        return null;
    }

    /**
     * 是否重复装配一样类型
     *
     * @return
     */
    public boolean isBoneRepeatEquip(UserVehicle userVehicle, int boneConfigId, int pos) {
        int checkType = 0;
        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(boneConfigId);
        if (goodsInfo != null) {
            checkType = VehicleBoneConfigMgr.getBonePosType(goodsInfo);
        }
        List<UserVehicleBone> boneList = getEquipBoneList(userVehicle.getVehicleUid());
        if (boneList == null) {
            return false;
        }
        for (UserVehicleBone userVehicleBone : boneList) {
            GoodsInfo checkGoodsInfo = GoodsMgr.getGoodsById(userVehicleBone.getConfigId());
            if (checkGoodsInfo == null) {
                continue;
            }

            if (userVehicleBone.getEquipPos() == pos && VehicleBoneConfigMgr.getBonePosType(checkGoodsInfo) == checkType) {//同个位置同个类型魂骨可以换
                return false;
            }

            if (VehicleBoneConfigMgr.getBonePosType(checkGoodsInfo) == checkType) {
                return true;
            }
        }

        return false;
    }

    /**
     * 珍兽装卸魂骨
     *
     * @return
     */
    public int equipBone(VehicleProto.VehicleBoneEquipReqMsg reqMsg) {
        if (!isSystemOpen()) {
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        String vehicleId = reqMsg.getVehicleId();
        int pos = reqMsg.getPos();
        int boneId = reqMsg.getBoneId();

        JSONObject beforeEquip = new JSONObject();//{槽位id，魂骨id，魂骨uid，阶位，[技能id=等级,技能id=等级,]}
        JSONObject afterEquip = new JSONObject();

        UserVehicle userVehicle = player.getModule(VehicleModule.class).getUserVehicle(vehicleId);
        if (userVehicle == null || userVehicle.isDelete()) {
            return GameErrorCode.E_VEHICLE_NO_FOUND;
        }

        if (!userVehicle.isBoneHoleUnlock(pos)) {
            return GameErrorCode.E_VEHICLE_BONE_POS_NOT_UNLOCK;
        }

        VehicleInfo vehicleInfo = VehicleMgr.getVehicleInfo(userVehicle.getTemplateId());
        if (vehicleInfo == null) {
            return GameErrorCode.E_VEHICLE_NO_FOUND;
        }

//        if (!VehicleBoneConfigMgr.isHoleUnlock(userVehicle.getBoneLv(), pos)) {
//            return GameErrorCode.E_VEHICLE_BONE_POS_NOT_UNLOCK;
//        }

        VehicleProto.VehicleBoneEquipRespMsg.Builder resp = VehicleProto.VehicleBoneEquipRespMsg.newBuilder();
        resp.setRet(0);

        UserVehicleBone vehicleEquipBone = getVehicleEquipBone(userVehicle, pos);

        if(reqMsg.getOperateType() == 0) {
            boolean canUnMountVehicleBone = player.getModule(VehicleModule.class).canUnMountVehicleBone(userVehicle.getVehicleUid(), boneId);
            if (!canUnMountVehicleBone) {
                return GameErrorCode.E_VEHICLE_BONE_BIND;
            }
        }

        if (reqMsg.getOperateType() > 0) {
            UserVehicleBone boneData = getBoneData(boneId);
            if (boneData == null) {
                return GameErrorCode.E_VEHICLE_BONE_NO_FOUND;
            }

            if (boneData.getVehicleId().equals(vehicleId)) {
                return GameErrorCode.E_VEHICLE_BONE_POS_EQUIP;
            }

            if (isBoneRepeatEquip(userVehicle, boneData.getConfigId(), pos)) {
                return GameErrorCode.E_VEHICLE_BONE_TYPE_REPEATED;
            }

            if (vehicleEquipBone != null) {//替换,卸下来

                boolean canUnMountVehicleBone = player.getModule(VehicleModule.class).canUnMountVehicleBone(userVehicle.getVehicleUid(), boneId);
                if (!canUnMountVehicleBone) {
                    return GameErrorCode.E_VEHICLE_BONE_BIND;
                }

                beforeEquip = LogVehicleBoneEquip.parseEquipObject(vehicleEquipBone);

                equipBoneMap.get(vehicleEquipBone.getVehicleId()).remove(vehicleEquipBone);

                vehicleEquipBone.unEquip();

                resp.addBone(VehicleBonePb.parseStoneTempBuilder(vehicleEquipBone));
            }

            if (!StringUtils.isNullOrEmpty(boneData.getVehicleId())) {
                UserVehicle beforeVehicle = player.getModule(VehicleModule.class).getUserVehicle(boneData.getVehicleId());
                if (beforeVehicle != null && beforeVehicle.getPatronsId() > 0) {
                    player.getModule(PatronsModule.class).syncPatronsCache(beforeVehicle.getPatronsId());
                }

                equipBoneMap.get(boneData.getVehicleId()).remove(boneData);
                boneData.unEquip();
            }

            boneData.setVehicleId(vehicleId);
            boneData.setEquipTime(DateHelper.getCurrentTime());
            boneData.setEquipPos(pos);

            afterEquip = LogVehicleBoneEquip.parseEquipObject(boneData);

            if (equipBoneMap.containsKey(vehicleId)) {
                equipBoneMap.get(vehicleId).add(boneData);
            } else {
                List<UserVehicleBone> boneList = new ArrayList<>();
                boneList.add(boneData);
                equipBoneMap.put(vehicleId, boneList);
            }

            resp.addBone(VehicleBonePb.parseStoneTempBuilder(boneData));
        } else {//不大于0都算卸
            if (vehicleEquipBone == null) {
                return GameErrorCode.E_VEHICLE_BONE_POS_NOT_EQUIP;
            }

            beforeEquip = LogVehicleBoneEquip.parseEquipObject(vehicleEquipBone);

            vehicleEquipBone.unEquip();

            equipBoneMap.get(vehicleId).remove(vehicleEquipBone);

            resp.addBone(VehicleBonePb.parseStoneTempBuilder(vehicleEquipBone));
        }

        if (userVehicle.getPatronsId() > 0) {
            player.getModule(PatronsModule.class).syncPatronsCache(userVehicle.getPatronsId());
        }

        player.sendPacket(GameProtocol.S_VBONE_EQUIP % 20000, resp);

        int combineAddQuantity = 0;
        if (userVehicle.getPatronsId() > 0) {
            player.getModule(PatronsModule.class).syncPatronsCache(userVehicle.getPatronsId());

            List<UserVehicleBone> equipBoneList = getEquipBoneList(vehicleId);
            combineAddQuantity = VehicleBoneConfigMgr.calcHoleFullAddQualification(userVehicle.getBoneLv(), equipBoneList, userVehicle.getBoneHole());
        }

        AutoLogMgr.add(new LogVehicleBoneEquip(player.getUserId(), userVehicle.getVehicleUid(), userVehicle.getTemplateId(),
                beforeEquip, afterEquip, combineAddQuantity));
        return 0;
    }

    public int skillLvUp(VehicleProto.VehicleBoneSkillUpReqMsg reqMsg) {
        if (!isSystemOpen()) {
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        UserVehicleBone boneData = getBoneData(reqMsg.getBoneId());
        if (boneData == null || boneData.isDelete()) {
            return GameErrorCode.E_VEHICLE_BONE_NO_FOUND;
        }

        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(boneData.getConfigId());
        if (goodsInfo == null) {
            return GameErrorCode.E_VEHICLE_BONE_NO_FOUND;
        }

        SkillInfo skillInfo = SkillMgr.getSkillInfo(reqMsg.getSkillId());
        if (skillInfo == null) {
            return GameErrorCode.E_VEHICLE_BONE_SKILL_NOT_FOUND;
        }

        if (!goodsInfo.getExtendParam().contains(String.valueOf(reqMsg.getSkillId()))) {
            return GameErrorCode.E_VEHICLE_BONE_SKILL_NOT_FOUND;
        }
        int startLv = boneData.getSkillLv(skillInfo.getId());

        Integer boneInitSkillId = VehicleBoneConfigMgr.getBoneInitSkillId(goodsInfo);
        int maxLevel = 0;
        if (startLv >= skillInfo.getMaxLevel()) {
            return GameErrorCode.E_LEVEL_MAX;
        }
        maxLevel = skillInfo.getMaxLevel();

        int endLv = startLv;
        Property preCost = new Property();
        Property realCost = new Property();
        for (endLv = startLv; endLv < startLv + reqMsg.getTimes() && endLv < maxLevel; endLv++) {
            SkillUpgradeInfo skillUpgradeInfo = SkillMgr.getSkillUpgradeInfo(skillInfo.getUpgradeType(0), endLv);
            if (skillUpgradeInfo == null) {
                break;
            }

            Property lvUpCost = new Property(skillInfo.getConsumeGoodsId().get(0), skillUpgradeInfo.getConsumeCount());
            preCost.addProperty(lvUpCost);
            if (!player.getModule(CurrencyModule.class).currencyIsEnough(preCost)) {
                break;
            }
            realCost.addProperty(lvUpCost);
        }
        if (endLv == startLv) {
            player.notifyListener(eGamePlayerEventType.VehicleBoneRechargeTrigger.getValue(), 0);
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        if (!player.getModule(CurrencyModule.class).removeCurrency(realCost, eLogMoneyType.VehicleBone, eLogMoneyType.VehicleBoneSkillLvUpCost)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        boneData.setSkillLv(skillInfo.getId(), endLv);

        VehicleProto.VehicleBoneSkillUpRespMsg.Builder resp = VehicleProto.VehicleBoneSkillUpRespMsg.newBuilder();
        resp.setRet(0);
        resp.setBone(VehicleBonePb.parseStoneTempBuilder(boneData));

        player.sendPacket(GameProtocol.S_VBONE_BONE_SKILL_UP % 20000, resp);

        if (!StringUtils.isNullOrEmpty(boneData.getVehicleId())) {
            UserVehicle userVehicle = player.getModule(VehicleModule.class).getUserVehicle(boneData.getVehicleId());
            if (userVehicle != null && userVehicle.getPatronsId() > 0) {
                player.getModule(PatronsModule.class).syncPatronsCache(userVehicle.getPatronsId());
            }
        }

        AutoLogMgr.add(new LogVehicleBoneSkillUp(player.getUserId(), boneData.getBoneId(), boneData.getConfigId(), boneData.getSkillLv(boneInitSkillId), skillInfo.getId(), endLv, realCost.toHelperString()));
        return 0;
    }

    public Property calcBoneResetReward(UserVehicleBone boneData) {
        Property reward = new Property();
        if (reward == null) {
            return reward;
        }

        //技能材料
        for (Map.Entry<Integer, Integer> entry : boneData.getSkillMap().entrySet()) {
            int skillId = entry.getKey();
            int skillLv = entry.getValue();
            Property skillConsume = SkillMgr.calcSkillLvTotalConsume(skillId, 0, skillLv, 0);
            reward.addProperty(skillConsume);
        }

        return reward;
    }

    public int recycle(List<Integer> boneIds) {
        if (!isSystemOpen()) {
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        List<Integer> logBoneIds = new ArrayList<>();
        List<Integer> logConfigIds = new ArrayList<>();

        Property totalReward = new Property();
        List<UserVehicleBone> changeList = new ArrayList<>();
        for (Integer boneId : boneIds) {
            UserVehicleBone boneData = getBoneData(boneId);
            if (boneData == null || boneData.isDelete()) {
                return GameErrorCode.E_VEHICLE_BONE_NO_FOUND;
            }

            GoodsInfo goodsInfo = GoodsMgr.getGoodsById(boneData.getConfigId());
            if (goodsInfo == null) {
                return GameErrorCode.E_VEHICLE_BONE_NO_FOUND;
            }

            if (!StringUtils.isNullOrEmpty(boneData.getVehicleId())) {
                return GameErrorCode.E_VEHICLE_BONE_POS_EQUIP;
            }

            Property resetReward = calcBoneResetReward(boneData);

            int star = VehicleBoneConfigMgr.getBoneStar(goodsInfo);
            Property boneRecycleReward = VehicleBoneConfigMgr.getBoneRecycleReward(star);

            resetReward.addProperty(boneRecycleReward);

            totalReward.addProperty(resetReward);

            changeList.add(boneData);
        }

        for (UserVehicleBone userVehicleBone : changeList) {
            userVehicleBone.setDelete(true);

            logBoneIds.add(userVehicleBone.getBoneId());
            logConfigIds.add(userVehicleBone.getConfigId());
        }


        player.getModule(CurrencyModule.class).addCurrency(totalReward, eLogMoneyType.VehicleBone, eLogMoneyType.VehicleBoneResetReward);


        VehicleProto.VehicleBoneRecycleRespMsg.Builder resp = VehicleProto.VehicleBoneRecycleRespMsg.newBuilder();
        resp.setRet(0);
        resp.setReward(totalReward.toHelperString());
        resp.addAllBoneId(boneIds);
        player.sendPacket(GameProtocol.S_VBONE_RECYCLE % 20000, resp);

        AutoLogMgr.add(new LogVehicleBoneRecycle(player.getUserId(), logBoneIds, logConfigIds, 2, resp.getReward()));
        return 0;
    }

    public int reset(int boneId) {
        if (!isSystemOpen()) {
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        UserVehicleBone boneData = getBoneData(boneId);
        if (boneData == null || boneData.isDelete()) {
            return GameErrorCode.E_VEHICLE_BONE_NO_FOUND;
        }

        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(boneData.getConfigId());
        if (goodsInfo == null) {
            return GameErrorCode.E_VEHICLE_BONE_NO_FOUND;
        }

//        if (!StringUtils.isNullOrEmpty(boneData.getVehicleId())) {
//            return GameErrorCode.E_VEHICLE_BONE_POS_EQUIP;
//        }
        long lastResetTime = player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.VehicleBoneLastResetTime);
        long currentTime = DateHelper.getCurrentTime();
        long passTime = currentTime - lastResetTime;
        if (passTime < GameConfig.SOUL_BONE_RESET_CD * DateHelper.HOUR_MILLIONS) {
            return GameErrorCode.E_VEHICLE_BONE_RESET_CD;
        }

        player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.VehicleBoneLastResetTime, currentTime);

        Property resetReward = calcBoneResetReward(boneData);

        boneData.reset(VehicleBoneConfigMgr.getBoneInitSkillId(goodsInfo));

        player.getModule(CurrencyModule.class).addCurrency(resetReward, eLogMoneyType.VehicleBone, eLogMoneyType.VehicleBoneResetReward);

        VehicleProto.VehicleBoneResetRespMsg.Builder resp = VehicleProto.VehicleBoneResetRespMsg.newBuilder();
        resp.setRet(0);
        resp.setReward(resetReward.toHelperString());
        resp.setBone(VehicleBonePb.parseStoneTempBuilder(boneData));
        player.sendPacket(GameProtocol.S_VBONE_RESET % 20000, resp);

        if (!StringUtils.isNullOrEmpty(boneData.getVehicleId())) {
            UserVehicle userVehicle = player.getModule(VehicleModule.class).getUserVehicle(boneData.getVehicleId());
            if (userVehicle != null && userVehicle.getPatronsId() != 0) {
                player.getModule(PatronsModule.class).syncPatronsCache(userVehicle.getPatronsId());
            }
        }

        AutoLogMgr.add(new LogVehicleBoneRecycle(player.getUserId(), Collections.singletonList(boneId), Collections.singletonList(boneData.getConfigId()), 1, resp.getReward()));
        return 0;
    }

    public void addBone(int goodsId, BigInteger num) {
        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(goodsId);
        if (goodsInfo == null) {
            return;
        }
        if (goodsInfo.getType() != eGoodsType.VehicleBone.getValue()) {
            return;
        }
        int star = VehicleBoneConfigMgr.getBoneStar(goodsInfo);
        if (star <= GameConfig.SOUL_BONE_RECLAIM_QUALITY) {
            //小于等于三星的回收
            Property boneRecycleReward = VehicleBoneConfigMgr.getBoneRecycleReward(star);
            boneRecycleReward.goodCountMultiNum(num.intValue());

            player.getModule(CurrencyModule.class).addCurrency(boneRecycleReward, eLogMoneyType.VehicleBone, eLogMoneyType.VehicleBoneRecycleReward);
        } else {
            List<UserVehicleBone> syncList = new ArrayList<>();
            for (int i = 0; i < num.intValue(); i++) {
                //初始技能
                Integer initSkillId = VehicleBoneConfigMgr.getBoneInitSkillId(goodsInfo);
                //初始技能从1级开始
                UserVehicleBone userVehicleBone = new UserVehicleBone(getUserId(), boneAtoId.getAndIncrement(), goodsId);
                userVehicleBone.setSkillLv(initSkillId, 1);
                boneMap.put(userVehicleBone.getBoneId(), userVehicleBone);

                syncList.add(userVehicleBone);
            }

            syncBoneData(syncList);
        }
    }

    public void vehicleUnEquipAllBone(String vehicleUid) {
        List<UserVehicleBone> equipBoneList = getEquipBoneList(vehicleUid);
        if (equipBoneList == null) {
            return;
        }

        for (UserVehicleBone userVehicleBone : equipBoneList) {
            userVehicleBone.unEquip();
            cacheSyncSet.add(userVehicleBone);
        }

        equipBoneMap.remove(vehicleUid);
    }

    public Map<String, List<UserVehicleBone>> getEquipBoneMap() {
        return equipBoneMap;
    }

    public int unlockHole(String vehicleUid, int pos) {
        if (!isSystemOpen()) {
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }

        if (pos <1 || pos > 32) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }

        UserVehicle userVehicle = player.getModule(VehicleModule.class).getUserVehicle(vehicleUid);
        if (userVehicle == null) {
            return GameErrorCode.E_VEHICLE_NO_FOUND;
        }
        VehicleInfo vehicleInfo = VehicleMgr.getVehicleInfo(userVehicle.getTemplateId());
        if (vehicleInfo == null) {
            return GameErrorCode.E_VEHICLE_NO_FOUND;
        }
        Property holeNumLimit = PropertyHelper.parseStringToProperty(GameConfig.SOUL_BONE_SLOT_NUM);
        if (pos > holeNumLimit.getCountByGoodsId(vehicleInfo.getBonePowerSkill()).intValue()){
            return GameErrorCode.E_VEHICLE_BONE_POS_NOT_UNLOCK;
        }
        if (!VehicleBoneConfigMgr.isHoleUnlock(userVehicle.getBoneLv(), pos)) {
            return GameErrorCode.E_VEHICLE_BONE_POS_NOT_UNLOCK;
        }
        List<UserVehicleBone> equipBoneList = getEquipBoneList(vehicleUid);
        int combineAddQuantity = VehicleBoneConfigMgr.calcHoleFullAddQualification(userVehicle.getBoneLv(), equipBoneList, userVehicle.getBoneHole());


        if (userVehicle.isBoneHoleUnlock(pos)) {
            return GameErrorCode.E_VEHICLE_BONE_POS_WAS_UNLOCK;
        }
        int holeValue = userVehicle.getBoneHole();

        int newHoleValue = holeValue | (1 << (pos - 1));
        userVehicle.setBoneHole(newHoleValue);

        VehicleProto.VehicleBoneHoleUnlockRespMsg.Builder resp = VehicleProto.VehicleBoneHoleUnlockRespMsg.newBuilder();
        resp.setRet(0);
        resp.setVehicle(VehiclePb.parseVehicleTempMsg(userVehicle));
        player.sendPacket(GameProtocol.S_VBONE_BONE_HOLE_UNLOCK % 20000, resp);

        int newCombineAddQuantity = VehicleBoneConfigMgr.calcHoleFullAddQualification(userVehicle.getBoneLv(), equipBoneList, userVehicle.getBoneHole());
        if (combineAddQuantity != newCombineAddQuantity && userVehicle.getPatronsId() > 0) {
            player.getModule(PatronsModule.class).syncPatronsCache(userVehicle.getPatronsId());
        }

        return 0;
    }

    public void finishChanges() {
        if (cacheSyncSet.isEmpty()){
            return;
        }
        syncBoneData(new ArrayList<>(cacheSyncSet));
    }
}


